﻿using Grow.Module.Service;
using Grow.Module.Thread;
using Grow.Utils.Exceptions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Collections.Concurrent;

namespace Grow.AspNetCore.Service
{
    public class ServiceContext : IServiceContext
    {

        private readonly ConcurrentDictionary<Type, Lazy<object?>> _services;

        private readonly IServiceProvider _serviceProvider;
        private readonly IServiceScopeFactory _serviceScopeFactory;

        public ServiceContext(IServiceProvider serviceProvider, IServiceScopeFactory serviceScopeFactory)
        {
            _services = new();

            _serviceProvider = serviceProvider;

            _serviceScopeFactory = serviceScopeFactory;
        }

        public ICancellationTokenContext GetCancellationTokenContext()
        {
            return GetRequiredService<ICancellationTokenContext>();
        }

        public TOptions GetOptions<TOptions>(string? key = null) where TOptions : class
        {
            return GetRequiredService<IOptionsMonitor<TOptions>>().Get(key);
        }


        public TService GetRequiredService<TService>() where TService : notnull
        {
            Type serviceType = typeof(TService);
            object? serviceObject = GetService(serviceType);
            return serviceObject is TService service ? service : throw new GrowFrameworkException($"类型为“{serviceType.FullName}”的服务无法找到");
        }

        public object GetRequiredService(Type serviceType)
        {
            object? serviceObject = GetService(serviceType);
            return serviceObject is not null ? serviceObject : throw new GrowFrameworkException($"类型为“{serviceType.FullName}”的服务无法找到");
        }

        public TService? GetService<TService>() where TService : notnull
        {
            Type serviceType = typeof(TService);
            object? serviceObject = GetService(serviceType);
            return serviceObject is TService service ? service : default;
        }

        public object? GetService(Type serviceType)
        {
            return _services.GetOrAdd(
              serviceType,
              _ => new Lazy<object?>(() => _serviceProvider.GetService(serviceType))
              ).Value;
        }
        public IEnumerable<TService> GetServices<TService>() where TService : notnull
        {
            return _serviceProvider.GetServices<TService>();
        }

        public IEnumerable<object?> GetServices(Type serviceType)
        {
            return _serviceProvider.GetServices(serviceType);
        }
        public IServiceContext GetServiceContext()
        {
            IServiceScope serviceScope = _serviceScopeFactory.CreateScope();
            return serviceScope.ServiceProvider.GetRequiredService<IServiceContext>();
        }


    }
}
